// Copyright (c) 2008 Matthew Johnson
// Licensed under the MIT License (see license.txt)
package actionml.display {
	import actionml.Global;

	import flash.display.DisplayObject;	
	import flash.display.DisplayObjectContainer;	
	import flash.display.MovieClip;
	import flash.filters.BitmapFilter;
	import flash.text.TextField;
		
	public class MovieClipMethods {
		public static function initialize() {
			Global.initializeExtension(MovieClipMethods, MovieClip);
		}
		public static var staticMethods:Object = {
			fromXML: function(xml:XML, stop:Boolean = true, root:DisplayObjectContainer = null) {
				root ||= Global.document;
				var t:Object = MovieClipMethods["getTracer"]({method:"fromXML", context:"xml"});
				var o:DisplayObject;
				var clipClass:Class;
				if (Object(xml).attribute("instanceName").length() == 1) {
					o = root.getChildByName(xml.@instanceName);
					if (!o) {
						t.error("The instance name '" + xml.@instanceName + "' does not represent a valid child instance of " + root + ".  This xml appears to be incorrect:\n\t" + Object(xml).toXMLString());
					}
				} else if (Object(xml).attribute("symbol").length() == 1) {
					clipClass = Object(Class).forName(xml.@symbol);
					if (clipClass) {
						o = new clipClass();
						if (o is DisplayObject) {
							root.addChild(o);
						} else {
							root[o.name] = o;
						}
					} else {
						t.error("The symbol name '" + xml.@symbol + "' does not represent a valid symbol.  This xml appears to be incorrect:\n\t" + Object(xml).toXMLString());
					}										
				} else {
					o = root.getChildByName(Object(xml).localName());
					if (o == null) {
						clipClass = Object(Class).forName(Object(xml).localName());
						if (clipClass) {
							o = new clipClass();
							if (o is DisplayObject) {
								root.addChild(o);
							} else {
								root[o.name] = o;
							}
						}
					}
				}
				if (o != null) {
					o.configureFromXML(xml, stop);
				} else {
					t.error("This xml should contain either an instanceName or a symbol attribute or the element name should match an instance name or symbol in your fla file.  It appears to be incorrect:\n\t" + Object(xml).toXMLString())
				}
				return o;
			}
		};
		public static var instanceMethods:Object = {
			playMedia: function() {
				this.playing = true;
				if (this.currentFrame == this.totalFrames) {
					this.gotoAndStop(0);
				}
				this.playToEnd();
				this.doEvent("play");
			},
			stopMedia: function() {
				this.playing = false;
				this.stop();
				this.doEvent("pause");
			},
			getBeginningLocation: function() {
				return 1;
			},
			getEndingLocation: function() {
				return this.totalFrames;
			},
			getLocation: function() {
				return this.currentFrame;
			},
			setLocation: function(l:int) {
				if (this.playing) {
					this.gotoAndPlay(l);
				} else {
					this.gotoAndStop(l);
				}
			},
			loadChildrenFromXML: function(xml:XML, stop:Boolean = true):MovieClip {
				var loaderMap:Object = {
					"tweens": "loadTweensFromXML",
					"expressions": "loadExpressionsFromXML",
					"actions": "parseActions"
				};
				var t:Object = MovieClipMethods["getTracer"]({method:"loadChildrenFromXML", context:"xml"});
				for each (var childXml:XML in Object(xml).elements()) {
					if (Object(childXml).localName() in loaderMap) {		
						this[loaderMap[Object(childXml).localName()]](childXml)
					} else {
						var child:DisplayObject = MovieClip["fromXML"](childXml, stop, this);
						if (child == null) {
							t.warn("No child of " + this + " could be loaded from the following xml:\n\t" + Object(childXml).elements());
							this[Object(childXml).localName()] = Object(childXml).toString().replace(new RegExp("^<" + Object(childXml).localName() + ">"), "").replace(new RegExp("</" + Object(childXml).localName() + ">$"), "");
							this["original" + Object(childXml).localName().toCapitalCase()] = childXml;
						}
					}
				}
			},
			loadTweensFromXML: function(xml:XML) {
				for each (var tweenXml:XML in Object(xml).elements()) {
					this.tweens ||= {};
					this.tweens[tweenXml.localName()] = this.loadTweenFromXml(tweenXml);
				}
			},
			loadTweenFromXml: function(xml:XML) {
				var tween:* = {name: Object(xml).localName(), target: this};
				var tweenAttributes:* = Object(xml).getAttributes();
				for each (var a in tweenAttributes.getPropertyNames()) {
					if (a == "playWhenFinished") {
						tween.playWhenFinished ||= [];
						for each (var t:String in tweenAttributes[a].split(/\s*,\s*/)) {
							tween.playWhenFinished.push(t);
						}
					} else {
						tween[a] = tweenAttributes[a];
					}
				}
				if (xml.playWhenFinished.length() > 0) {
					for each (var whenFinishedXml:XML in xml.playWhenFinished["elements"]()) {
						tween.playWhenFinished ||= [];
						tween.playWhenFinished.push(arguments.callee(whenFinishedXml));
					}
				}
				return new (Class["forName"]("actionml.animation.Tween"))(tween);  // precompile
			},
			loadExpressionsFromXML: function(xml:XML) {
				var attributes:Object = Object(xml).getAttributes();
				for (var expressionName:String in attributes) {
					var expression:Object = attributes[expressionName].compileExpression();
					this["get" + expressionName.toCapitalCase()] = function() {
						return this.evaluateExpression(expression);
					}
				}
			}
		};
	}
}